/*                          UX-Framework                               
 *                                                                 
 *  iZE Co.,Ltd. Copyright 2009 All rights reserved.          
 *  This file is distributed under the terms of the GNU Lesser 
 *  General Public License, described in file LICENSE.                                     
 */
package jp.ize.ux.components;

// {{{ imports
import jp.ize.ux.SWFAddress;
import jp.ize.ux.UXObject;
import jp.ize.ux.UXController;
import jp.ize.ux.UXInteraction;
import jp.ize.ux.UXFocusManager;
import jp.ize.ux.acts.Act;
import jp.ize.ux.components.UXComponent;
import jp.ize.ux.components.UXComponentResource;
import jp.ize.ux.interactions.UXGeneralInteraction;
import jp.ize.ux.states.UXBasicState;
import jp.ize.ux.events.UXMouseEvent;
import jp.ize.ux.events.UXKeyboardEvent;
import jp.ize.ux.geom.UXPoint;

#if flash9
import flash.ui.Keyboard;
#elseif flash
import flash.Key;
#end
// }}}
// {{{ enum SceneChangeType
enum SceneChangeType
{
	/** 通常タイプです。 */
	NORMAL;
	/** サブシーンとして変化します。現在のシーンに追加オーバーレイする形で遷移します。 */
	SUB;
}
// }}}
// {{{ typedef SceneInfo
typedef SceneInfo =
{
	/**
	* /（スラッシュ）をルートとし、/（スラッシュ）区切りの英小文字と数字で構成されたURLに似た名前
	* 最後の文字も/（スラッシュ）で終わるようにします。
	*/
	var name:String;
	/** どのようにこのシーンに変化するかを指定します */
	var type:SceneChangeType;
	/** シーンを定義するUXSceneを継承したクラス */
	var klass:Dynamic;
}
// }}}
// {{{ class UXSceneManagerState
/**
 * UXSceneManagerState クラス<br>
 */
//class UXSceneManagerState extends UXBasicState
class UXSceneManagerState extends UXBasicState
{
	// {{{ public var session(default, default) : Hash<Dynamic>
	/**
	 * セッションの値保存用の変数です。
	 */
	public var session(default, default) : Hash<Dynamic>;
	// }}}
	// {{{ public var formdata(default, default) : UXFormData
	/**
	 * UXFormDataのインスタンスです。
	 */
	public var formdata(default, default) : UXFormData;
	// }}}
	// {{{ public var tempdata(default, default) : UXFormData
	/**
	 * UXFormDataのインスタンスです。
	 * シーン間のデータ受け渡しのため等に一時的に利用するためのものです。
	 */
	public var tempdata(default, default) : UXFormData;
	// }}}
	// {{{ public var currScene(default, default) : UXScene
	/**
	 * 現在のシーンです。
	 */
	public var currScene(default, default) : UXScene;
	// }}}
	// {{{ public var currSceneName(default, default) : String
	/**
	 * 現在のシーン名です。
	 */
	public var currSceneName(default, default) : String;
	// }}}
	// {{{ public var prevScene(default, default) : UXScene
	/**
	 * 前のシーンです。
	 */
	public var prevScene(default, default) : UXScene;
	// }}}
	// {{{ public var prevSceneName(default, default) : String
	/**
	 * 前のシーン名です。
	 */
	public var prevSceneName(default, default) : String;
	// }}}
	// {{{ public var sceneInfos(default, default) : Hash<SceneInfo>;
	/**
	 * シーン情報の集合です。
	 */
	public var sceneInfos(default, default) : Hash<SceneInfo>;
	// }}}
	// {{{ public function new( scenes:Array<SceneInfo> ) : Void
	/**
	 * コンストラクタです。
	 */
	public function new( scenes:Array<SceneInfo> ) : Void
	{
		super();
		this.currScene = null;
		this.prevScene = null;
		this.sceneInfos = new Hash();
		this.session    = new Hash();
		this.formdata   = new UXFormData();
		for ( s in scenes ) {
			sceneInfos.set( s.name, s );
		}
	}
	// }}}
}
// }}}

// {{{ class UXSceneManager extends UXComponent
/**
 * UXSceneManager クラス<br>
 *
 * UXSceneの状態を管理しながら、現在の画面がどういう状態かを表すオブジェクトです。
 * UXSceneによる画面遷移はメモリ管理上、遷移の度に表示を毎回作成、廃棄します。
 * シーンの登録のためには、UXSceneを継承したクラスを登録します。
 * 遷移されたときに、コンストラクタにてインスタンスを生成して、UXScene::view() メソッドを呼出します。
 * 内部でSWFAdressを使用しています。SWFAddressがシングルトンなため、
 * 以前に設定した内容を上書きしてしまいますので注意が必要です。
 *
 * @author		iZE Co., Ltd.<br>
 * @version		$Id: UXScene.hx 20 2009-02-04 08:23:19Z yimai.v $<br>
 */
class UXSceneManager extends UXComponent<UXSceneManagerState>
{
	// {{{ properties

	public var base:UXBasicComponent;

	// }}}
	// {{{ public var session(getSession,setSession) : Hash<Dynamic>;
	/**
	* state.session にアクセスします。
	*/
	public var session(getSession,setSession) : Hash<Dynamic>;
	// }}}
	// {{{ public function new( scenes:Array<SceneInfo> ) : Void
	/**
	 * コンストラクタです。
	 * @param scenes: シーン情報の配列を指定します。
	 */
	public function new( scenes:Array<SceneInfo> ) : Void
	{
		// レイアウトとアクトのインスタンスを作ります。
		base = new UXBasicComponent();
		state = new UXSceneManagerState(scenes);
		state.target = this;
		ctrl = new UXController<UXSceneManagerState>( state );
		ctrl.addInteraction( new UXSceneManagerSceneChangeInteraction() );
		super(ctrl);
		addUXChild(base);
		var me = this;
		ctrl.getInteraction("SceneChange").setActSequentialMode(true);
		ctrl.getInteraction("SceneChange").addAct(function(s){
			// {{{ currScene view
			var func = function() {
				if ( s.sceneInfos.exists(s.currSceneName) ) {
					var sceneInfo = s.sceneInfos.get(s.currSceneName);
					var scene = cast(Type.createInstance(sceneInfo.klass,[me]),UXScene);
					scene.ctrl.getInteraction("PreView").addFinishHandler(function(s){
						scene.view();
					});
					scene.ctrl.trigger("PreView");
					switch ( sceneInfo.type ) {
						case NORMAL:
							s.currScene = scene;
							if ( s.prevScene!=null ) {
								for ( sub in s.prevScene.scenes ) {
									s.prevScene.removeUXScene(sub);
								}
								me.removeUXChild(s.prevScene);
							}
							me.addUXChild(s.currScene);
						case SUB:
							s.currScene = s.prevScene;
							s.prevScene.ctrl.getInteraction("PreView").removeFinishHandler();
							s.prevScene.ctrl.getInteraction("PreView").addFinishHandler(function(state){
								s.currScene.addUXScene(scene);
							});
							s.prevScene.ctrl.trigger("PreView");
					}
				}
			}
			// }}}
			if ( s.prevScene!=null ) {
				s.prevScene.ctrl.getInteraction("PostView").removeFinishHandler();
				s.prevScene.ctrl.getInteraction("PostView").addFinishHandler(function(s){func();});
				s.prevScene.ctrl.trigger("PostView");
			} else {
				func();
			}
		});
		var me = this;
		SWFAddress.onChange = function() {
			var val = SWFAddress.getValue();
			var qstr = SWFAddress.getQueryString();
			//trace(qstr);
			val = StringTools.replace(val,"?","");
			val = StringTools.replace(val,qstr,"");
			//trace(val);
			var prev = me.state.currSceneName;
			me.state.currSceneName = val;
			me.state.prevSceneName = prev;
			me.state.prevScene = me.state.currScene;
			me.state.currScene = null;
			me.ctrl.trigger("SceneChange");
		}
		SWFAddress.init();
	}
	// }}}
	// {{{ public funciton getSession() : Hash<Dynamic>
	/*
	* セッション格納用変数を取得します。
	*/
	public function getSession() : Hash<Dynamic>
	{
		return state.session;
	}

	// }}}
	// {{{ public funciton setSession( s:Hash<Dynamic> ) : Hash<Dynamic>
	/*
	* セッション格納用変数を設定します。
	*/
	public function setSession( s:Hash<Dynamic> ) : Hash<Dynamic>
	{
		state.session = s;
		return state.session;
	}

	// }}}
	// {{{ public function change( name:String ) : Void
	/**
	* 指定した name の画面に遷移します。
	*/
	public function change( name:String ) : Void
	{
		SWFAddress.setValue(name);
	}

	// }}}
	// {{{ public function refreshResource() : Void
	/**
	 * アイテムに対するグローバルなリソースを再取得する関数です。
	 */
	public function refreshResource() : Void
	{
	}
	// }}}
	// {{{ public function update( updator : UXSceneManagerState -> Void ) : Void
	/**
	 * このコンポーネントの状態を直接変更するメソッドです。状態のどんな操作も可能になるので、
	 * このメソッドの使用には注意が必要です。
	 */
	public function update( updator : UXSceneManagerState -> Void ) : Void
	{
		updator( state );
	}
	// }}}
	// {{{ public function addSceneInfo( info:SceneInfo ) : Void
	/**
	* シーン情報を追加します。
	*/
	public function addSceneInfo( info:SceneInfo ) : Void
	{
		state.sceneInfos.set( info.name, info );
	}

	// }}}
	// {{{ public function removeSceneInfo( info:SceneInfo ) : Void
	/**
	* シーン情報を削除します。
	*/
	public function removeSceneInfo( info:SceneInfo ) : Void
	{
		if ( state.sceneInfos.exists( info.name ) ) {
			state.sceneInfos.remove( info.name );
		}
	}

	// }}}
	// {{{ public function getFormData() : UXFormData
	/**
	* このシーンの持つUXFormDataのインスタンスを取得します。
	*/
	public function getFormData() : UXFormData
	{
		return state.formdata;
	}

	// }}}
	// {{{ public function getFormValues() : Hash<String>
	/**
	* formdataから値を取得します。
	*/
	public function getFormValues() : Hash<String>
	{
		return state.formdata.values;
	}

	// }}}
	// {{{ public function setFormValues( v:Hash<String> ) : Void
	/**
	* formdataに値を設定します。
	*/
	public function setFormValues( v:Hash<String> ) : Void
	{
		state.formdata.values = v;
	}

	// }}}
	// {{{ public function getValue( key:String ) : String
	/**
	* keyを指定して、valuesから値を外部に取得します。
	*/
	public function getValue( key:String ) : String
	{
		return state.formdata.getValue(key);
	}

	// }}}
	// {{{ public function setValue( key:String, val:String ) : Void
	/**
	* keyを指定して、内部のvaluesに値を設定します。
	*/
	public function setValue( key:String, val:String ) : Void
	{
		state.formdata.setValue(key,val);
	}

	// }}}
}
// }}}

// {{{ class UXSceneManagerSceneChangeInteraction extends UXGeneralInteraction<UXSceneManagerState>
/**
 * UXSceneManagerChangeInteraction クラス<br>
 * アイテムの実行に対するデフォルトインタラクションです。
 */
class UXSceneManagerSceneChangeInteraction extends UXGeneralInteraction<UXSceneManagerState>
{
	// {{{ public function new() : Void
	/**
	* コンストラクタ
	*/
	public function new() : Void
	{
		super("SceneChange");
		this.judge = function(s) {
			return s.enabled;
		}
	}

	// }}}
}
// }}}
